﻿using Rj_GsInsurance.Server.Enums;
using Rj_GsInsurance.Server.Models;
using Rj_GsInsurance.Server.Models.InsurMsgDataOutput;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Text;
using System.Text.Json;
using System.Threading.Tasks;

namespace Rj_GsInsurance.Server.Extensions
{
    public static class InsurMsgExtensions
    {
        public static string SerializerInsurMsgData<T>(this T insurMsgData)
        {
            if(insurMsgData==null)
                return string.Empty;
            Type type=insurMsgData.GetType();
            PropertyInfo[] propertyInfos = default;
            if (type.IsGenericType && type == typeof(List<>))
            {
                Type itemType = type.GetGenericArguments()[0];
                propertyInfos = itemType.GetProperties();
            }
            else
            {
                propertyInfos = type.GetProperties();
            }

            if (type.IsGenericType && type.Name == typeof(List<>).Name)
            {
                IEnumerable list = insurMsgData as IEnumerable;
                List<string> resultList = new List<string>();
                foreach (var item in list)
                {
                    string resultStr= SerializerInsurMsgData(item, propertyInfos, '|');
                    resultList.Add(resultStr);
                }
                return $"{string.Join('$', resultList)}";
            }
            else
            {
                return SerializerInsurMsgData(insurMsgData, propertyInfos, '|');
            }
        }

        public static string SerializerInsurMsgData(object param, PropertyInfo[] propertyInfos, char separator)
        {
            List<string> strings = new List<string>();
            for (int i = 0; i < propertyInfos.Length; i++)
            {
                var propertyInfo = propertyInfos[i];
                var noSerializerAttribute=propertyInfo.GetCustomAttribute<NoSerializerAttribute>();
                if(noSerializerAttribute != null)
                {
                    continue;
                }
                var value = propertyInfo.GetValue(param);
                if (propertyInfo.PropertyType == typeof(DateTime?))
                {
                    DateTime? dateTime = ((DateTime?)value);
                    strings.Add(dateTime.HasValue ? dateTime.Value.ToString("yyyy-MM-dd HH:mm:ss") : "");
                }
                else if (propertyInfo.PropertyType == typeof(DateTime))
                {
                    DateTime dateTime = ((DateTime)value);
                    strings.Add(dateTime.ToString("yyyy-MM-dd HH:mm:ss"));
                }
                else
                {
                    strings.Add(value?.ToString() ?? "");
                }
            }

            return $"{string.Join(separator, strings)}"+ separator;
        }

        public static T DeserializeInsurMsgData<T>(string msg)
        {
            Type type=typeof(T);
            T insurMsgData=(T)Activator.CreateInstance(type);
            PropertyInfo[] propertyInfos = default;
            if (type.IsGenericType && type.Name == typeof(List<>).Name)
            {
                IList list=insurMsgData as IList;
                Type itemType = type.GetGenericArguments()[0];
                propertyInfos = itemType.GetProperties();
                foreach (var item in msg.Split('$',StringSplitOptions.RemoveEmptyEntries))
                {
                    object obj = Activator.CreateInstance(itemType);
                    string[] strings = item.Split("|");
                    int len = strings.Length <= propertyInfos.Length ? strings.Length : propertyInfos.Length;
                    for (int i = 0; i < len; i++)
                    {
                        var propertyInfo = propertyInfos[i];
                        string value = strings[i];
                        object objValue = default;
                        if (propertyInfo.PropertyType == typeof(DateTime?))
                        {
                            DateTime? dateTime = DateTime.Parse(value);
                            objValue = dateTime;
                        }
                        else if (propertyInfo.PropertyType == typeof(DateTime))
                        {
                            DateTime dateTime = DateTime.Parse(value);
                            objValue = dateTime;
                        }
                        else
                        {
                            objValue = Convert.ChangeType(value, propertyInfo.PropertyType);
                        }
                        propertyInfos[i].SetValue(obj, objValue);
                    }
                    list.Add(obj);
                }
                return insurMsgData;
            }
            else
            {
                propertyInfos = type.GetProperties();
                string[] strings = msg.Split("|");
                int len = strings.Length <= propertyInfos.Length ? strings.Length : propertyInfos.Length;
                for (int i = 0; i < len; i++)
                {
                    var propertyInfo = propertyInfos[i];
                    string value = strings[i];
                    object objValue = default;
                    if (propertyInfo.PropertyType == typeof(DateTime?))
                    {
                        DateTime? dateTime = DateTime.Parse(value);
                        objValue = dateTime;
                    }
                    else if (propertyInfo.PropertyType == typeof(DateTime))
                    {
                        DateTime dateTime = DateTime.Parse(value);
                        objValue = dateTime;
                    }
                    else
                    {
                        objValue = Convert.ChangeType(value, propertyInfo.PropertyType);
                    }
                    propertyInfos[i].SetValue(insurMsgData, objValue);
                }
                return insurMsgData;
            }
        }

        public static string SerializerInsurMsg<T>(this InsurMsgIn<T> insurMsg)
        {
            Type type = insurMsg.GetType();
            var propertyInfos = type.GetProperties();
            string[] strings = new string[propertyInfos.Length];
            for (int i = 0; i < propertyInfos.Length; i++)
            {
                var propertyInfo = propertyInfos[i];
                var value = propertyInfo.GetValue(insurMsg);
                if (propertyInfo.PropertyType == typeof(DateTime?))
                {
                    DateTime? dateTime = ((DateTime?)value);
                    strings[i] = dateTime.HasValue ? dateTime.Value.ToString("yyyy-MM-dd HH:mm:ss") : "";
                }
                else if (propertyInfo.PropertyType == typeof(DateTime))
                {
                    DateTime dateTime = ((DateTime)value);
                    strings[i] = dateTime.ToString("yyyy-MM-dd HH:mm:ss");
                }else if (propertyInfo.PropertyType == typeof(T))
                {
                    strings[i]= SerializerInsurMsgData((T)value);
                }
                else
                {
                    strings[i] = value?.ToString();
                }
            }

            return $"{string.Join('^', strings)}^";
        }

        public static InsurMsgOut<Out> DeserializeInsurMsg<Out>(string msg)
        {
            InsurMsgOut<Out> insurMsgOut = new InsurMsgOut<Out>();
            Type type= insurMsgOut.GetType();
            var propertyInfos = type.GetProperties();
            string[] strings = msg.Split("^");
            int len = strings.Length <= propertyInfos.Length ? strings.Length : propertyInfos.Length;
            for (int i = 0; i < len; i++)
            {
                var propertyInfo = propertyInfos[i];
                string value = strings[i];
                object objValue=default;
                if (propertyInfo.PropertyType == typeof(DateTime?))
                {
                    DateTime? dateTime = DateTime.Parse(value);
                    objValue = dateTime;
                }
                else if (propertyInfo.PropertyType == typeof(DateTime))
                {
                    DateTime dateTime = DateTime.Parse(value);
                    objValue = dateTime;
                }
                else if (propertyInfo.PropertyType == typeof(Out))
                {
                    objValue=DeserializeInsurMsgData<Out>(value);
                }
                else
                {
                    objValue = Convert.ChangeType(value, propertyInfo.PropertyType);
                }
                propertyInfos[i].SetValue(insurMsgOut, objValue);
            }
            return insurMsgOut;
        }

        public static async Task<InsurMsgOut<Out>> ExcuteSync<In, Out>(this In insurMsgData, string tranCode)
        {
            return await Task.Run(() => {
                return Excute<In, Out>(insurMsgData, tranCode);
            });
        }

        public static InsurMsgOut<Out> Excute<In,Out>(this In insurMsgData,string tranCode)
        {
            InsurMsgIn<In> signIn = new InsurMsgIn<In>()
            {
                ywbh = "9100",
                gsxyjgbh = "42050330102",
                czybh = "26",
                gsxyjgjylsh=$"{DateTime.Now.ToString("yyyyMMddHHmmss")}-42050330102-0001",
                zxbm = "0000",
                input = default,
                ljbz = "1"
            };
            var signOutMsg=signIn.Excute<SignOutput>();
            

            InsurMsgIn<In> insurMsgIn = new InsurMsgIn<In>()
            {
                ywbh = tranCode,//"2100",
                gsxyjgbh = "42050330102",
                czybh = "26",
                ywzqh= signOutMsg.output.ywzqh,
                gsxyjgjylsh = $"{DateTime.Now.ToString("yyyyMMddHHmmss")}-42050330102-0001",
                zxbm = "0000",
                input = insurMsgData,
                ljbz = "1"
            };
            return insurMsgIn.Excute<Out>();
        }
    }
}
